// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.core.skinnedmodel.model;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.opengl.GL20;
import org.lwjgl.system.MemoryUtil;
import org.lwjglx.BufferUtils;
import zombie.core.VBO.IGLBufferObject;
import zombie.core.opengl.RenderThread;
import zombie.core.skinnedmodel.shader.Shader;
import zombie.debug.DebugOptions;
import zombie.util.list.PZArrayUtil;

public final class VertexBufferObject {
    public static IGLBufferObject funcs;
    int[] elements;
    VertexBufferObject.Vbo _handle;
    private final VertexBufferObject.VertexFormat m_vertexFormat;
    private VertexBufferObject.BeginMode _beginMode;
    public boolean bStatic = false;

    public VertexBufferObject() {
        this.bStatic = false;
        this.m_vertexFormat = new VertexBufferObject.VertexFormat(4);
        this.m_vertexFormat.setElement(0, VertexBufferObject.VertexType.VertexArray, 12);
        this.m_vertexFormat.setElement(1, VertexBufferObject.VertexType.NormalArray, 12);
        this.m_vertexFormat.setElement(2, VertexBufferObject.VertexType.ColorArray, 4);
        this.m_vertexFormat.setElement(3, VertexBufferObject.VertexType.TextureCoordArray, 8);
        this.m_vertexFormat.calculate();
        this._beginMode = VertexBufferObject.BeginMode.Triangles;
    }

    @Deprecated
    public VertexBufferObject(VertexPositionNormalTangentTexture[] vertexPositionNormalTangentTexture, int[] _int) {
        this.elements = _int;
        this.bStatic = true;
        RenderThread.invokeOnRenderContext(
            this,
            vertexPositionNormalTangentTexture,
            _int,
            (vertexBufferObject1, vertexPositionNormalTangentTexturex, _intx) -> vertexBufferObject1._handle = this.LoadVBO(
                    vertexPositionNormalTangentTexturex, _intx
                )
        );
        this.m_vertexFormat = new VertexBufferObject.VertexFormat(4);
        this.m_vertexFormat.setElement(0, VertexBufferObject.VertexType.VertexArray, 12);
        this.m_vertexFormat.setElement(1, VertexBufferObject.VertexType.NormalArray, 12);
        this.m_vertexFormat.setElement(2, VertexBufferObject.VertexType.TangentArray, 12);
        this.m_vertexFormat.setElement(3, VertexBufferObject.VertexType.TextureCoordArray, 8);
        this.m_vertexFormat.calculate();
        this._beginMode = VertexBufferObject.BeginMode.Triangles;
    }

    @Deprecated
    public VertexBufferObject(VertexPositionNormalTangentTextureSkin[] vertexPositionNormalTangentTextureSkin, int[] int0, boolean _boolean) {
        this.elements = int0;
        if (_boolean) {
            int[] int1 = new int[int0.length];
            byte _byte = 0;

            for (int int2 = int0.length - 1 - 2; int2 >= 0; int2 -= 3) {
                int1[_byte] = int0[int2];
                int1[_byte + 1] = int0[int2 + 1];
                int1[_byte + 2] = int0[int2 + 2];
                _byte += 3;
            }

            int0 = int1;
        }

        this.bStatic = false;
        this._handle = this.LoadVBO(vertexPositionNormalTangentTextureSkin, int0);
        this.m_vertexFormat = new VertexBufferObject.VertexFormat(6);
        this.m_vertexFormat.setElement(0, VertexBufferObject.VertexType.VertexArray, 12);
        this.m_vertexFormat.setElement(1, VertexBufferObject.VertexType.NormalArray, 12);
        this.m_vertexFormat.setElement(2, VertexBufferObject.VertexType.TangentArray, 12);
        this.m_vertexFormat.setElement(3, VertexBufferObject.VertexType.TextureCoordArray, 8);
        this.m_vertexFormat.setElement(4, VertexBufferObject.VertexType.BlendWeightArray, 16);
        this.m_vertexFormat.setElement(5, VertexBufferObject.VertexType.BlendIndexArray, 16);
        this.m_vertexFormat.calculate();
        this._beginMode = VertexBufferObject.BeginMode.Triangles;
    }

    public VertexBufferObject(VertexBufferObject.VertexArray vertexArray, int[] _int) {
        this.m_vertexFormat = vertexArray.m_format;
        this.elements = _int;
        this.bStatic = true;
        RenderThread.invokeOnRenderContext(
            this, vertexArray, _int, (vertexBufferObject1, vertexArrayx, _intx) -> vertexBufferObject1._handle = this.LoadVBO(vertexArrayx, _intx)
        );
        this._beginMode = VertexBufferObject.BeginMode.Triangles;
    }

    public VertexBufferObject(VertexBufferObject.VertexArray vertexArray, int[] int1, boolean _boolean) {
        this.m_vertexFormat = vertexArray.m_format;
        if (_boolean) {
            int[] int0 = new int[int1.length];
            byte _byte = 0;

            for (int int2 = int1.length - 1 - 2; int2 >= 0; int2 -= 3) {
                int0[_byte] = int1[int2];
                int0[_byte + 1] = int1[int2 + 1];
                int0[_byte + 2] = int1[int2 + 2];
                _byte += 3;
            }

            int1 = int0;
        }

        this.elements = int1;
        this.bStatic = false;
        this._handle = this.LoadVBO(vertexArray, int1);
        this._beginMode = VertexBufferObject.BeginMode.Triangles;
    }

    @Deprecated
    private VertexBufferObject.Vbo LoadVBO(VertexPositionNormalTangentTextureSkin[] vertexPositionNormalTangentTextureSkin, int[] int1) {
        VertexBufferObject.Vbo vbo = new VertexBufferObject.Vbo();
        int int0 = 0;
        byte _byte = 76;
        vbo.FaceDataOnly = false;
        ByteBuffer byteBuffer0 = BufferUtils.createByteBuffer(vertexPositionNormalTangentTextureSkin.length * _byte);
        ByteBuffer byteBuffer1 = BufferUtils.createByteBuffer(int1.length * 4);

        for (int int2 = 0; int2 < vertexPositionNormalTangentTextureSkin.length; int2++) {
            vertexPositionNormalTangentTextureSkin[int2].put(byteBuffer0);
        }

        for (int int3 = 0; int3 < int1.length; int3++) {
            byteBuffer1.putInt(int1[int3]);
        }

        byteBuffer0.flip();
        byteBuffer1.flip();
        vbo.VboID = funcs.glGenBuffers();
        funcs.glBindBuffer(funcs.GL_ARRAY_BUFFER(), vbo.VboID);
        funcs.glBufferData(funcs.GL_ARRAY_BUFFER(), byteBuffer0, funcs.GL_STATIC_DRAW());
        funcs.glGetBufferParameter(funcs.GL_ARRAY_BUFFER(), funcs.GL_BUFFER_SIZE(), vbo.b);
        int0 = vbo.b.get();
        if (vertexPositionNormalTangentTextureSkin.length * _byte != int0) {
            throw new RuntimeException("Vertex data not uploaded correctly");
        } else {
            vbo.EboID = funcs.glGenBuffers();
            funcs.glBindBuffer(funcs.GL_ELEMENT_ARRAY_BUFFER(), vbo.EboID);
            funcs.glBufferData(funcs.GL_ELEMENT_ARRAY_BUFFER(), byteBuffer1, funcs.GL_STATIC_DRAW());
            vbo.b.clear();
            funcs.glGetBufferParameter(funcs.GL_ELEMENT_ARRAY_BUFFER(), funcs.GL_BUFFER_SIZE(), vbo.b);
            int0 = vbo.b.get();
            if (int1.length * 4 != int0) {
                throw new RuntimeException("Element data not uploaded correctly");
            } else {
                vbo.NumElements = int1.length;
                vbo.VertexStride = _byte;
                return vbo;
            }
        }
    }

    public VertexBufferObject.Vbo LoadSoftwareVBO(ByteBuffer byteBuffer2, VertexBufferObject.Vbo vbo1, int[] int0) {
        VertexBufferObject.Vbo vbo0 = vbo1;
        boolean _boolean = false;
        ByteBuffer byteBuffer0 = null;
        if (vbo1 == null) {
            _boolean = true;
            vbo0 = new VertexBufferObject.Vbo();
            vbo0.VboID = funcs.glGenBuffers();
            ByteBuffer byteBuffer1 = BufferUtils.createByteBuffer(int0.length * 4);

            for (int int1 = 0; int1 < int0.length; int1++) {
                byteBuffer1.putInt(int0[int1]);
            }

            byteBuffer1.flip();
            byteBuffer0 = byteBuffer1;
            vbo0.VertexStride = 36;
            vbo0.NumElements = int0.length;
        } else {
            vbo1.b.clear();
        }

        vbo0.FaceDataOnly = false;
        funcs.glBindBuffer(funcs.GL_ARRAY_BUFFER(), vbo0.VboID);
        funcs.glBufferData(funcs.GL_ARRAY_BUFFER(), byteBuffer2, funcs.GL_STATIC_DRAW());
        funcs.glGetBufferParameter(funcs.GL_ARRAY_BUFFER(), funcs.GL_BUFFER_SIZE(), vbo0.b);
        if (byteBuffer0 != null) {
            vbo0.EboID = funcs.glGenBuffers();
            funcs.glBindBuffer(funcs.GL_ELEMENT_ARRAY_BUFFER(), vbo0.EboID);
            funcs.glBufferData(funcs.GL_ELEMENT_ARRAY_BUFFER(), byteBuffer0, funcs.GL_STATIC_DRAW());
        }

        return vbo0;
    }

    @Deprecated
    private VertexBufferObject.Vbo LoadVBO(VertexPositionNormalTangentTexture[] vertexPositionNormalTangentTexture, int[] int1) {
        VertexBufferObject.Vbo vbo = new VertexBufferObject.Vbo();
        int int0 = 0;
        byte _byte = 44;
        vbo.FaceDataOnly = false;
        ByteBuffer byteBuffer0 = BufferUtils.createByteBuffer(vertexPositionNormalTangentTexture.length * _byte);
        ByteBuffer byteBuffer1 = BufferUtils.createByteBuffer(int1.length * 4);

        for (int int2 = 0; int2 < vertexPositionNormalTangentTexture.length; int2++) {
            vertexPositionNormalTangentTexture[int2].put(byteBuffer0);
        }

        for (int int3 = 0; int3 < int1.length; int3++) {
            byteBuffer1.putInt(int1[int3]);
        }

        byteBuffer0.flip();
        byteBuffer1.flip();
        vbo.VboID = funcs.glGenBuffers();
        funcs.glBindBuffer(funcs.GL_ARRAY_BUFFER(), vbo.VboID);
        funcs.glBufferData(funcs.GL_ARRAY_BUFFER(), byteBuffer0, funcs.GL_STATIC_DRAW());
        funcs.glGetBufferParameter(funcs.GL_ARRAY_BUFFER(), funcs.GL_BUFFER_SIZE(), vbo.b);
        int0 = vbo.b.get();
        if (vertexPositionNormalTangentTexture.length * _byte != int0) {
            throw new RuntimeException("Vertex data not uploaded correctly");
        } else {
            vbo.EboID = funcs.glGenBuffers();
            funcs.glBindBuffer(funcs.GL_ELEMENT_ARRAY_BUFFER(), vbo.EboID);
            funcs.glBufferData(funcs.GL_ELEMENT_ARRAY_BUFFER(), byteBuffer1, funcs.GL_STATIC_DRAW());
            vbo.b.clear();
            funcs.glGetBufferParameter(funcs.GL_ELEMENT_ARRAY_BUFFER(), funcs.GL_BUFFER_SIZE(), vbo.b);
            int0 = vbo.b.get();
            if (int1.length * 4 != int0) {
                throw new RuntimeException("Element data not uploaded correctly");
            } else {
                vbo.NumElements = int1.length;
                vbo.VertexStride = _byte;
                return vbo;
            }
        }
    }

    private VertexBufferObject.Vbo LoadVBO(VertexBufferObject.VertexArray vertexArray, int[] int0) {
        VertexBufferObject.Vbo vbo = new VertexBufferObject.Vbo();
        vbo.FaceDataOnly = false;
        ByteBuffer byteBuffer = MemoryUtil.memAlloc(int0.length * 4);

        for (int int1 = 0; int1 < int0.length; int1++) {
            byteBuffer.putInt(int0[int1]);
        }

        vertexArray.m_buffer.position(0);
        vertexArray.m_buffer.limit(vertexArray.m_numVertices * vertexArray.m_format.m_stride);
        byteBuffer.flip();
        vbo.VboID = funcs.glGenBuffers();
        funcs.glBindBuffer(funcs.GL_ARRAY_BUFFER(), vbo.VboID);
        funcs.glBufferData(funcs.GL_ARRAY_BUFFER(), vertexArray.m_buffer, funcs.GL_STATIC_DRAW());
        funcs.glGetBufferParameter(funcs.GL_ARRAY_BUFFER(), funcs.GL_BUFFER_SIZE(), vbo.b);
        int int2 = vbo.b.get();
        if (vertexArray.m_numVertices * vertexArray.m_format.m_stride != int2) {
            throw new RuntimeException("Vertex data not uploaded correctly");
        } else {
            vbo.EboID = funcs.glGenBuffers();
            funcs.glBindBuffer(funcs.GL_ELEMENT_ARRAY_BUFFER(), vbo.EboID);
            funcs.glBufferData(funcs.GL_ELEMENT_ARRAY_BUFFER(), byteBuffer, funcs.GL_STATIC_DRAW());
            MemoryUtil.memFree(byteBuffer);
            vbo.b.clear();
            funcs.glGetBufferParameter(funcs.GL_ELEMENT_ARRAY_BUFFER(), funcs.GL_BUFFER_SIZE(), vbo.b);
            int2 = vbo.b.get();
            if (int0.length * 4 != int2) {
                throw new RuntimeException("Element data not uploaded correctly");
            } else {
                vbo.NumElements = int0.length;
                vbo.VertexStride = vertexArray.m_format.m_stride;
                return vbo;
            }
        }
    }

    public void clear() {
        if (this._handle != null) {
            if (this._handle.VboID > 0) {
                funcs.glDeleteBuffers(this._handle.VboID);
                this._handle.VboID = -1;
            }

            if (this._handle.EboID > 0) {
                funcs.glDeleteBuffers(this._handle.EboID);
                this._handle.EboID = -1;
            }

            this._handle = null;
        }
    }

    public void Draw(Shader shader) {
        Draw(this._handle, this.m_vertexFormat, shader, 4);
    }

    public void DrawStrip(Shader shader) {
        Draw(this._handle, this.m_vertexFormat, shader, 5);
    }

    private static void Draw(VertexBufferObject.Vbo vbo, VertexBufferObject.VertexFormat vertexFormat, Shader shader, int int4) {
        if (vbo != null) {
            if (!DebugOptions.instance.DebugDraw_SkipVBODraw.getValue()) {
                int int0 = 33984;
                boolean _boolean = false;
                if (!vbo.FaceDataOnly) {
                    funcs.glBindBuffer(funcs.GL_ARRAY_BUFFER(), vbo.VboID);

                    for (int int1 = 0; int1 < vertexFormat.m_elements.length; int1++) {
                        VertexBufferObject.VertexElement vertexElement = vertexFormat.m_elements[int1];
                        switch (vertexElement.m_type) {
                            case VertexArray:
                                GL20.glVertexPointer(3, 5126, vbo.VertexStride, (long)vertexElement.m_byteOffset);
                                GL20.glEnableClientState(32884);
                                break;
                            case NormalArray:
                                GL20.glNormalPointer(5126, vbo.VertexStride, (long)vertexElement.m_byteOffset);
                                GL20.glEnableClientState(32885);
                                break;
                            case ColorArray:
                                GL20.glColorPointer(3, 5121, vbo.VertexStride, (long)vertexElement.m_byteOffset);
                                GL20.glEnableClientState(32886);
                                break;
                            case TextureCoordArray:
                                GL20.glActiveTexture(int0);
                                GL20.glClientActiveTexture(int0);
                                GL20.glTexCoordPointer(2, 5126, vbo.VertexStride, (long)vertexElement.m_byteOffset);
                                int0++;
                                GL20.glEnableClientState(32888);
                            case TangentArray:
                            default:
                                break;
                            case BlendWeightArray:
                                int int2 = shader.BoneWeightsAttrib;
                                GL20.glVertexAttribPointer(int2, 4, 5126, false, vbo.VertexStride, (long)vertexElement.m_byteOffset);
                                GL20.glEnableVertexAttribArray(int2);
                                _boolean = true;
                                break;
                            case BlendIndexArray:
                                int int3 = shader.BoneIndicesAttrib;
                                GL20.glVertexAttribPointer(int3, 4, 5126, false, vbo.VertexStride, (long)vertexElement.m_byteOffset);
                                GL20.glEnableVertexAttribArray(int3);
                        }
                    }
                }

                funcs.glBindBuffer(funcs.GL_ELEMENT_ARRAY_BUFFER(), vbo.EboID);
                GL20.glDrawElements(int4, vbo.NumElements, 5125, 0L);
                GL20.glDisableClientState(32885);
                if (_boolean && shader != null) {
                    int int5 = shader.BoneWeightsAttrib;
                    GL20.glDisableVertexAttribArray(int5);
                    int5 = shader.BoneIndicesAttrib;
                    GL20.glDisableVertexAttribArray(int5);
                }
            }
        }
    }

    public static enum BeginMode {
        Triangles;
    }

    public static final class Vbo {
        public final IntBuffer b = BufferUtils.createIntBuffer(4);
        public int VboID;
        public int EboID;
        public int NumElements;
        public int VertexStride;
        public boolean FaceDataOnly;
    }

    public static final class VertexArray {
        public final VertexBufferObject.VertexFormat m_format;
        public final int m_numVertices;
        public final ByteBuffer m_buffer;

        public VertexArray(VertexBufferObject.VertexFormat format, int numVertices) {
            this.m_format = format;
            this.m_numVertices = numVertices;
            this.m_buffer = BufferUtils.createByteBuffer(this.m_numVertices * this.m_format.m_stride);
        }

        public void setElement(int vertex, int element, float v1, float v2) {
            int _int = vertex * this.m_format.m_stride + this.m_format.m_elements[element].m_byteOffset;
            this.m_buffer.putFloat(_int, v1);
            _int += 4;
            this.m_buffer.putFloat(_int, v2);
        }

        public void setElement(int vertex, int element, float v1, float v2, float v3) {
            int _int = vertex * this.m_format.m_stride + this.m_format.m_elements[element].m_byteOffset;
            this.m_buffer.putFloat(_int, v1);
            _int += 4;
            this.m_buffer.putFloat(_int, v2);
            _int += 4;
            this.m_buffer.putFloat(_int, v3);
        }

        public void setElement(int vertex, int element, float v1, float v2, float v3, float v4) {
            int _int = vertex * this.m_format.m_stride + this.m_format.m_elements[element].m_byteOffset;
            this.m_buffer.putFloat(_int, v1);
            _int += 4;
            this.m_buffer.putFloat(_int, v2);
            _int += 4;
            this.m_buffer.putFloat(_int, v3);
            _int += 4;
            this.m_buffer.putFloat(_int, v4);
        }

        float getElementFloat(int int3, int int2, int int1) {
            int int0 = int3 * this.m_format.m_stride + this.m_format.m_elements[int2].m_byteOffset + int1 * 4;
            return this.m_buffer.getFloat(int0);
        }
    }

    public static final class VertexElement {
        public VertexBufferObject.VertexType m_type;
        public int m_byteSize;
        public int m_byteOffset;
    }

    public static final class VertexFormat {
        final VertexBufferObject.VertexElement[] m_elements;
        int m_stride;

        public VertexFormat(int numElements) {
            this.m_elements = PZArrayUtil.newInstance(VertexBufferObject.VertexElement.class, numElements, VertexBufferObject.VertexElement::new);
        }

        public void setElement(int index, VertexBufferObject.VertexType type, int byteSize) {
            this.m_elements[index].m_type = type;
            this.m_elements[index].m_byteSize = byteSize;
        }

        public void calculate() {
            this.m_stride = 0;

            for (int _int = 0; _int < this.m_elements.length; _int++) {
                this.m_elements[_int].m_byteOffset = this.m_stride;
                this.m_stride = this.m_stride + this.m_elements[_int].m_byteSize;
            }
        }
    }

    public static enum VertexType {
        VertexArray,
        NormalArray,
        ColorArray,
        IndexArray,
        TextureCoordArray,
        TangentArray,
        BlendWeightArray,
        BlendIndexArray;
    }
}
